package ar.com.arkios.kfconTraductor;

import ar.com.arkios.j4d.opConstants;
import ar.com.arkios.j4d.opException;
import ar.com.arkios.j4d.opProcess;
import ar.com.arkios.j4d.opServerProcess;
import ar.com.arkios.j4d.opServerProcessArray;
import ar.com.arkios.kfcon4d.Connection4D;
import ar.com.arkios.kfcon4d.util.CuatroDUtils;
import ar.com.arkios.kfconTraductor.util.Timer;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.util.ArrayList;
import java.util.List;
import org.apache.log4j.Logger;

/**
 * 
 */
public class MainServer {
    
    private static final Logger miLogger = Logger.getLogger(MainServer.class);

    private static final int PUERTO = 50777;
    
    private static final int BACKLOG = 10;
    
    private static final int TIMEOUT_ACCEPT = 2000; // 2 segundos
    
    private static ServerSocket serverSocket;
    
    private static boolean parar = false;
    
    private static List<ClientHandler> clientes;
    
    private static Connection4D miConexion;
    private static opProcess miProceso;
    private static opServerProcess miStoreProc;
    
    public static synchronized void Parar() {
        parar = true;
    }
    
    private static synchronized boolean getParar() {
        return parar;
    }
    
    public static void enviarEstado(String elMensaje) {
        try {
            CuatroDUtils.SetTextVar(miProceso, "KFConStatus", opConstants.VPROCESS, miStoreProc, elMensaje);
        } catch (opException ex) {
            miLogger.error("No se pudo enviar mensaje de estado al KF, mensaje: "+elMensaje+". Motivo: "+ex.GetErrorMsg());
        }
    }

    public static void enviarResulado(String elMensaje) {
        try {
            CuatroDUtils.SetTextVar(miProceso, "KFConResultado", opConstants.VPROCESS, miStoreProc, elMensaje);
        } catch (opException ex) {
            miLogger.error("No se pudo enviar mensaje de resultado al KF, mensaje: "+elMensaje+". Motivo: "+ex.GetErrorMsg());
        }
    }

    public static void enviarResuladoPallet(String elMensaje) {
        try {
            CuatroDUtils.SetTextVar(miProceso, "KFConResultadoPallet", opConstants.VPROCESS, miStoreProc, elMensaje);
        } catch (opException ex) {
            miLogger.error("No se pudo enviar mensaje de resultado pallet al KF, mensaje: "+elMensaje+". Motivo: "+ex.GetErrorMsg());
        }
    }

    public static void enviarTexto(String elMensaje, String laVariableNombre) {
        try {
            CuatroDUtils.SetTextVar(miProceso, laVariableNombre, opConstants.VPROCESS, miStoreProc, elMensaje);
        } catch (opException ex) {
            miLogger.error("No se pudo enviar mensaje de resultado al KF, mensaje: "+elMensaje+". Motivo: "+ex.GetErrorMsg());
        }
    }

    public static opServerProcess getMiStoreProc() {
        return miStoreProc;
    }
    
    public static void main(String [] args){
        // aca mandar alguna señal al 4D
        int cantVueltas = 0;//Creado para detectar errores en ejecucion.
        try {
            miLogger.info("*--------* Server KFCon v1.14 Lanzado *----------*");
            serverSocket = new ServerSocket(PUERTO, BACKLOG);
            serverSocket.setSoTimeout(TIMEOUT_ACCEPT);
            clientes = new ArrayList<ClientHandler>();
            Socket socketCliente = null;
            miConexion = Connection4D.getInstance();
            miProceso = miConexion.getMyProcess();
            miLogger.info("Conexión a 4D Server establecida");
            try {
                opServerProcessArray losProc = miProceso.GetProcessList();
                for (opServerProcess proc : losProc.mServerProcessArray) {
                    if (proc.mProcessName.equals("ExpoStoredProc")) {
                        miProceso.GetProcessNumber(proc);
                        miStoreProc = proc;
                        break;
                    }
                }
                enviarEstado("KFConnector On Line");
                miLogger.info("Conexión StoredProcedure establecida");
//            String elStatus = CuatroDUtils.GetStringVar(miProceso, "KFConStatus", opConstants.VPROCESS, miStoreProc);
//            CuatroDUtils.SetTextVar(miProceso, "KFConStatus", opConstants.VPROCESS, miStoreProc, "On Line");
//            String elStatus2 = CuatroDUtils.GetStringVar(miProceso, "KFConStatus2", opConstants.VPROCESS, miStoreProc);
//            CuatroDUtils.SetStringVar(miProceso, "KFConStatus2", opConstants.VPROCESS, miStoreProc, "On Line 2");
            } catch (opException ex) {
                miLogger.error("No se pudo establecer conexión a StoredProcedure: " + ex.GetErrorMsg());
            }
            //----------------------------------------------
            while (!getParar()) {
                cantVueltas++;

                try {
                    socketCliente = serverSocket.accept();
                    ClientHandler clientHandler = new ClientHandler(socketCliente);
                    clientHandler.start();
                    clientes.add(clientHandler);
                } catch (SocketTimeoutException e) {
                    // No se conectó nadie.
                    if(cantVueltas%50==0){
                        miLogger.debug("MainServer: Nada recibido en el socket. Cantidad Vueltas: "+cantVueltas+".");
                    }

                }
                // Limpio los clientes que no estén mas activos.                
                if (!clientes.isEmpty()) {
                    List<ClientHandler> clientesRemover = new ArrayList<ClientHandler>();
                    for (ClientHandler clientHandler : clientes) {
                        if (!clientHandler.isActivo()) {
                            clientesRemover.add(clientHandler);
                        }
                    }
                    for (ClientHandler clientHandler : clientesRemover) {
                        clientes.remove(clientHandler);
                        miLogger.debug("Se removio el cliente (" + clientHandler.getSocket().getInetAddress() + ":" + clientHandler.getSocket().getPort() + ")");
                    }
                }
            }

            //Agregado 18-05-09 por Ale IT 1393. Obligo a que no me cierren si aun hay conexiones con 4d.
            miLogger.debug("MainServer: Mientras no hayan clientes activos prosigue con el cierre del conector.");
            Timer aTimer = new Timer(1000*60*2, "No se pudieron remover los clientes.");
            aTimer.start();
            while(!clientes.isEmpty()){
                List<ClientHandler> clientesRemover = new ArrayList<ClientHandler>();
                for (ClientHandler clientHandler : clientes) {
                    if (!clientHandler.isActivo()) {
                        clientesRemover.add(clientHandler);
                    }
                }
                for (ClientHandler clientHandler : clientesRemover) {
                    clientes.remove(clientHandler);
                    miLogger.debug("Se removio el cliente (" + clientHandler.getSocket().getInetAddress() + ":" + clientHandler.getSocket().getPort() + ")");
                }
            }
            aTimer.reset();
            miLogger.debug("MainServer: No habian mas clientes se prosigue con el cierre del conector.");
            // aca mandar alguna señal al 4D
            try {
                enviarEstado("KFConnector Finalizando");
                miConexion.closeConnection();
                miLogger.info("Se envio Mensaje a 4D de Conector Finalizado y se cerro la conexion con 4d.");
            } finally {
                miLogger.info("*--------* Server KFCon v1.14 Finalizado *----------*");
                System.exit(0);
            }
        } catch (IOException ex) {
            miLogger.info("Se produjo un Error IO Se termina la ejecución de KFCon");
            miLogger.info("Mensaje Exception: "+ex.getMessage());
            System.exit(0);//Ver que mensaje podemos enviar de Salida.
        }catch(Exception e){
            miLogger.info("Se produjo un Error Inesperado en KFCon. Se Termina la Ejecución de KFCon.");
            miLogger.info("Mensaje Exception: "+e.getMessage());
            System.exit(0);//Ver que mensaje podemos enviar de Salida.
        }
    }
    
}
